#pragma once
#include "EventLoop.hpp"
#include "ThreadPool.hpp"
#include "TcpConnection.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
class TcpServer
{
public:
    TcpServer(unsigned short port, int threadNum)
    {
        m_port = port;
        m_mainLoop = new EventLoop;
        m_threadNum = threadNum;
        m_threadPool = new ThreadPool(m_mainLoop, threadNum);
        setListen();
    }
    ~TcpServer()
    {
    }
    // 初始化监听的文件描述符
    void setListen()
    {
        // 1.创建监听fd
        m_lfd = socket(AF_INET, SOCK_STREAM, 0);

        // 2.设置端口复用
        int opt = 1;
        int ret = setsockopt(m_lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        // 设置lfd可以复用绑定的端口，当服务器程序是主动断开的一方，有一个2MSL的等待时长（约1min)
        // 才能释放绑定端口。释放前是不能使用的
        // 所以需要设置端口复用，在2MSL期间就可以使用绑定的端口

        // 3.绑定
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(m_port);
        addr.sin_addr.s_addr = INADDR_ANY;
        bind(m_lfd, (struct sockaddr *)&addr, sizeof(addr));

        // 4.设置监听
        listen(m_lfd, 128);
    }
    // 启动服务器
    void run()
    {
        // 启动线程池
        m_threadPool->run();
        // 添加检测任务
        // 初始化一个channel实例
        Channel *channel = new Channel(m_lfd, FDEvent::ReadEvent, acceptConnection, nullptr, nullptr, this);
        m_mainLoop->addTask(channel, ElemType::ADD);
        // 启动反应堆模型
        m_mainLoop->run();
    }

    static int acceptConnection(void *arg)
    {
        TcpServer *server = static_cast<TcpServer *>(arg);
        // 和客户端建立连接
        int cfd = accept(server->m_lfd, nullptr, nullptr);
        // 从线程池中去一个子线程的反应堆实例
        class EventLoop *evLoop = server->m_threadPool->takeWorkerEventLoop();
        // 将cfd放到TcpConnection中处理
        new TcpConnetion(cfd, evLoop);
        return 0;
    }

private:
    int m_threadNum;
    class EventLoop *m_mainLoop;
    ThreadPool *m_threadPool;
    int m_lfd;
    unsigned short m_port;
};
